using System.Diagnostics;
using FluentParser.Expressions;

namespace FluentParser.Expressions.Rules.Composition
{
    /// <summary>
    /// This expression is successful only if the three children can be
    /// successfully parsed in a sequence from left to right.
    /// </summary>
    /// <typeparam name="T">Type of the resulting value</typeparam>
    /// <example><code>
    /// var text = ParseString.Regex("[A-Za-z]+");
    /// var surroundedText = text.Surround("(", ")");
    /// 
    /// text.Parse("SomeText")             --> "SomeText"
    /// text.Parse("1234")                 --> failure
    /// surroundedText.Parse("SomeText")   --> failure
    /// surroundedText.Parse("(SomeText)") --> "SomeText"
    /// surroundedText.Parse("(1234)")     --> failure
    /// </code></example>
    [DebuggerDisplay("[SurroundExpressionRule {Left} + {Center} + {Right}]")]
    public class SurroundExpressionRule<T> : Expr<T> 
    {
        public Symbol Left { get; private set; }
        public Expr<T> Center { get; private set; }
        public Symbol Right { get; private set; }

        public SurroundExpressionRule(Symbol left, Expr<T> center, Symbol right)
        {
            Left = left;
            Center = center;
            Right = right;
            TypeOperation = OperationType.Grouping;
        }

        public override ParsingResult<T> Parse(GrammarContext context, int index)
        {
            ParsingResult<object> resultLeft = Left.Parse(context, index);
            if (resultLeft != null)
            {
                ParsingResult<T> resultCenter = Center.Parse(context, resultLeft.End);
                if (resultCenter != null)
                {
                    ParsingResult<object> resultRight = Right.Parse(context, resultCenter.End);
                    if (resultRight != null)
                        return new ParsingResult<T>(index, resultLeft.Length + resultCenter.Length + resultRight.Length,
                                                    resultCenter.Value);
                }
            }

            return null;
        }

        public override void ParseNode(GrammarContext context, ParsingNodeResult node)
        {
            ParsingNodeResult leftNode = node.AddChild(Left, context);
            if (leftNode.IsSuccess)
            {
                ParsingNodeResult centerNode = node.AddChild(Center, context, leftNode.End);
                if (centerNode.IsSuccess)
                {
                    ParsingNodeResult rightNode = node.AddChild(Right, context, centerNode.End);
                    if (rightNode.IsSuccess)
                    {
                        node.Value = centerNode.Value;
                        node.IsSuccess = true;
                    }
                    else
                    {
                        node.Length = 0;
                    }
                }
                else
                {
                    node.Length = 0;
                }
            }
        }
    }
}